import numpy as np
import open3d as o3d

class ReconstructionMethod:
    """重建方法枚举（便于UI选择）"""
    BPA = "BPA球旋转算法"
    ALPHA_SHAPES = "Alpha Shapes算法"
    
    @staticmethod
    def get_all_methods():
        """获取所有支持的重建方法"""
        return [
            ReconstructionMethod.BPA,
            ReconstructionMethod.ALPHA_SHAPES
        ]

class PointCloudReconstructor:
    """点云重建工具类（集中所有重建方法）"""
    @staticmethod
    def reconstruct(point_cloud_data, method: str):
        """
        统一重建接口
        :param point_cloud_data: (M,3) 点云数据
        :param method: 重建方法（来自ReconstructionMethod）
        :return: 重建后的网格对象（Open3D TriangleMesh）、顶点数据（N,3）
        """
        if method == ReconstructionMethod.BPA:
            return PointCloudReconstructor.bpa_reconstruct(point_cloud_data)
        elif method == ReconstructionMethod.ALPHA_SHAPES:
            return PointCloudReconstructor.alpha_shapes_reconstruct(point_cloud_data)
        else:
            raise ValueError(f"不支持的重建方法：{method}")

    @staticmethod
    def bpa_reconstruct(point_cloud_data):
        """第一种方法：BPA球旋转算法重建"""
        # 创建Open3D点云对象
        pcd = o3d.geometry.PointCloud()
        pcd.points = o3d.utility.Vector3dVector(point_cloud_data)
        
        # 估计法线（BPA重建必需）
        pcd.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0.1, max_nn=30))
        
        # BPA重建核心参数（可根据点云密度调整）
        radii = [0.005, 0.01, 0.02, 0.04]
        bpa_mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_ball_pivoting(
            pcd, o3d.utility.DoubleVector(radii)
        )
        
        # 优化网格（去除重复顶点和三角形）
        bpa_mesh.remove_duplicated_vertices()
        bpa_mesh.remove_duplicated_triangles()
        bpa_mesh.compute_vertex_normals()  # 重新计算法线，提升可视化效果
        
        # 提取顶点数据（用于主界面显示）
        vertices = np.asarray(bpa_mesh.vertices)
        print(f"BPA重建完成：顶点数={len(vertices)}，三角形数={len(bpa_mesh.triangles)}")
        return bpa_mesh, vertices

    @staticmethod
    def alpha_shapes_reconstruct(point_cloud_data):
        """第二种方法：Alpha Shapes算法重建"""
        # 创建Open3D点云对象
        pcd = o3d.geometry.PointCloud()
        pcd.points = o3d.utility.Vector3dVector(point_cloud_data)
        
        # 可选下采样（根据点数自适应，避免重建过慢）
        if point_cloud_data.shape[0] > 10000:
            pcd = pcd.voxel_down_sample(voxel_size=0.01)
            print(f"Alpha Shapes：点云下采样后点数={len(pcd.points)}")
        
        # 估计法线（提升重建质量）
        pcd.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0.1, max_nn=30))
        
        # Alpha Shapes重建核心参数（可调整，值越小网格越精细）
        alpha = 0.01
        alpha_mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_alpha_shape(pcd, alpha)
        
        # 优化网格
        alpha_mesh.remove_duplicated_vertices()
        alpha_mesh.remove_duplicated_triangles()
        alpha_mesh.compute_vertex_normals()
        
        # 提取顶点数据
        vertices = np.asarray(alpha_mesh.vertices)
        print(f"Alpha Shapes重建完成：顶点数={len(vertices)}，三角形数={len(alpha_mesh.triangles)}")
        return alpha_mesh, vertices